package com.gxljc.bear.crawler.related;

import java.io.IOException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Date;

/**
 * To find out all the movies in the same series
 * 
 * @author yubiao,yihao
 * @since 2015.6.1
 * 
 */
public class FindSeriesMovie {
	// ***********************************************************************SETTING
	// test or not******
	private final static boolean test = false;
	static boolean is_unsure;
	static boolean is_set;

	// get info inside "";
	private static String GetInfo(String s) {
		String temp;
		Pattern pattern = Pattern.compile("\\S*\\\"(.+)\\\"\\S*");
		Matcher macther = pattern.matcher(s);
		if (macther.matches()) {
			temp = macther.group(1);
			if (temp.substring(0, 1).equals("\""))
				temp = temp.substring(1, temp.length());
			if (temp.substring(temp.length() - 1, temp.length()).equals("\""))
				temp = temp.substring(0, temp.length() - 1);
			return temp;
		} else {
			if (s.length() > 1) {
				if (s.substring(0, 1).equals("\""))
					s = s.substring(1, s.length());
				if (s.substring(s.length() - 1, s.length()).equals("\""))
					s = s.substring(0, s.length() - 1);
			}
			return s;
		}

	}

	// split one line of record string based on "," and return useful string
	// array;
	private static String[] splitt(String str) {
		String[] abc = str.split(",");
		int len = abc.length;
		String[] newstr = new String[13];
		for (int i = 0; i < 12; i++) {
			if (i >= 8)
				newstr[i] = GetInfo(abc[i + 1]);
			else
				newstr[i] = GetInfo(abc[i]);
		}
		newstr[12] = GetInfo(abc[len - 2]);
		return newstr;
	}

	// split the title to get the common name;
	private static String split_title(String str) {
		String[] abc = str.split("：");
		str = abc[0];
		abc = str.split(":");
		str = abc[0];
		String[] abc2 = str.split(" ");
		str = abc2[0];
		return str;
	}

	// split the title from zhi
	private static String split_title2(String str) {
		String[] abc = str.split("之");
		str = abc[0];
		return str;
	}

	// get the number of the title
	private static String[] getNumAndSetitle(String str) {
		String[] back_str = new String[2];
		String[] abc = str.split("：");
		str = abc[0];
		if (abc.length > 1)
			back_str[1] = abc[1];
		else
			back_str[1] = "NULL";
		if (back_str[1].equals("NULL")) {
			abc = str.split(":");
			str = abc[0];
			if (abc.length > 1)
				back_str[1] = abc[1];
			else
				back_str[1] = "NULL";
		}
		// will cause many wrong judgment.
		/*
		 * if(back_str[1].equals("NULL")){ abc=str.split("之"); str=abc[0];
		 * if(abc.length>1) back_str[1]=abc[1]; else back_str[1]="NULL"; }
		 */
		if (str.length() > 0)
			if (Character.isDigit(str.charAt(str.length() - 1)))
				if (str.length() > 1)
					// suppose there will be no more than 100 series
					if (Character.isDigit(str.charAt(str.length() - 2)))
						if (str.length() > 2)
							if (Character.isDigit(str.charAt(str.length() - 3)))
								back_str[0] = "NULL";
							else
								back_str[0] = str.substring(str.length() - 2,
										str.length());
						else
							back_str[0] = "NULL";
					else
						back_str[0] = str.substring(str.length() - 1,
								str.length());
				else
					back_str[0] = "NULL";
			else
				back_str[0] = "NULL";
		else
			back_str[0] = "NULL";
		return back_str;
	}

	// transform string to number;
	private static int[] str2int(String str, int len1) {
		int[] temp = new int[str.length() + 1];
		temp[0] = 1;
		int biggest_index = 1;
		for (int i = 1; i < str.length(); i++) {
			for (int j = 0; j < i; j++)
				if (str.substring(i, i + 1).equals(str.substring(j, j + 1)))
					temp[i] = temp[j];
			if (temp[i] == 0) {
				temp[i] = biggest_index + 1;
				biggest_index = biggest_index + 1;
			}
			if (i == len1 - 1)
				temp[str.length()] = biggest_index;
		}
		return temp;
	}

	/**
	 * compare 2 string and return the similarity rate;
	 * 
	 * @param str1
	 * @param str2
	 * @param id
	 * @return
	 */
	private static double calculate_similarity(String str1, String str2, int id) {
		double rate = 0;
		if (str1.equals("NULL") || str2.equals("NULL"))
			return rate;
		// special way to cope with director,writer,actors and type;
		if (id == 4 || id == 5 || id == 6 || id == 7) {
			String[] abc1 = str1.split("#");
			String[] abc2 = str2.split("#");
			int len1 = abc1.length;
			int len2 = abc2.length;
			/*
			 * for(int j=0;j<len1;j++){ abc1[j]=abc1[j].split("-")[0]; } for(int
			 * j=0;j<len2;j++){ abc1[j]=abc2[j].split("-")[0]; }
			 */
			int count = 0;
			if (len1 >= len2) {
				for (int i = 0; i < len2; i++)
					for (int j = 0; j < len1; j++) {
						if (abc2[i].equals(abc1[j])) {
							count = count + 1;
							break;
						}
					}
				if (id == 6) {
					rate = (double) count / 3;
					if (rate > 1)
						rate = 1;
				} else
					rate = (double) count / len1;
			} else {
				for (int i = 0; i < len1; i++)
					for (int j = 0; j < len2; j++) {
						if (abc1[i].equals(abc2[j])) {
							count = count + 1;
							break;
						}
					}
				if (id == 6) {
					rate = (double) count / 3;
					if (rate > 1)
						rate = 1;
				} else
					rate = (double) count / len2;
			}
			return rate;
		}
		int len1 = str1.length();
		int len2 = str2.length();
		// we made str1's length always bigger than str2;
		if (len1 < len2) {
			String str = str1;
			str1 = str2;
			str2 = str;
		}
		int index2 = str1.length();
		String str = str1 + str2;
		int[] myint = new int[str.length() + 1];
		// int biggest_index=str2int(str1,str1.length())[str1.length()];
		// int[] pos=new int[str2.length()];
		int same_num = 0;
		myint = str2int(str, str1.length());
		int biggest_index = myint[str.length()];
		for (int i = 0; i < str2.length(); i++) {
			if (myint[index2 + i] <= biggest_index) {
				same_num = same_num + 1;
			}
		}
		rate = (double) same_num / str1.length();
		return rate;
	}

	// return the biggest one;
	private static double max(double a, double b, double c) {
		if (a >= b)
			if (a >= c)
				return a;
			else
				return c;
		else if (b >= c)
			return b;
		else
			return c;
	}

	// compare whether two record is for the same series;
	private static boolean is_sameSeries(String[] str1, String[] str2) {
		double similarity = 0;
		// set the weight of each element for year the same;\
		// ***********************************************************************SETTING
		// weight******
		final double weight_title = 0.4;
		final double weight_actors = 0.4;
		final double weight_type = 0.1;
		final double weight_dict = 0.05;
		final double weight_language = 0.05;
		// set the weight of each element for year not the same;
		final double weight_title2 = 0.35;
		final double weight_actors2 = 0.35;
		final double weight_type2 = 0.025;
		final double weight_dict2 = 0.05;
		final double weight_language2 = 0.025;
		final double weight_director_writer = 0.2;
		// set the threshold for judging whether is the same series;
		// ***********************************************************************SETTING
		// threshold******
		final double threshold = 0.65;
		// first-class judgment;
		if (!str1[12].equals(str2[12]) || str1[10].equals(str2[10]))
			return false;
		// second-class judgment;
		else if (str1[3] == str2[3]) {
			// third-class judgment;
			if (calculate_similarity(str1[4], str2[4], 4) < 0.8
					|| calculate_similarity(str1[5], str2[5], 5) < 0.8)
				return false;
			// fourth-class judgment;
			else {
				similarity += max(
						calculate_similarity(str1[1], str2[1], 1),
						calculate_similarity(split_title2(str1[1]),
								split_title2(str2[1]), 1), 0)
						* weight_title;
				// calculate_similarity(str1[2],str2[2]),
				// calculate_similarity(str1[11],str2[11]))*weight_title;
				similarity += calculate_similarity(str1[6], str2[6], 6)
						* weight_actors;
				similarity += calculate_similarity(str1[7], str2[7], 7)
						* weight_type;
				similarity += calculate_similarity(str1[8], str2[8], 8)
						* weight_dict;
				similarity += calculate_similarity(str1[9], str2[9], 9)
						* weight_language;
				if (test)
					System.out.print(similarity + " ");
				if (similarity >= threshold) {
					if (!is_set) {
						if (max(calculate_similarity(str1[1], str2[1], 1),
								calculate_similarity(split_title2(str1[1]),
										split_title2(str2[1]), 1), 0) < 0.3
								&& calculate_similarity(str1[6], str2[6], 6) > 0.8) {
							is_unsure = true;
							is_set = true;
						}
					}
					return true;
				} else
					return false;
			}
		} else
		// fourth-class judgment;
		{
			similarity += max(
					calculate_similarity(str1[1], str2[1], 1),
					calculate_similarity(split_title2(str1[1]),
							split_title2(str2[1]), 1), 0)
					* weight_title2;
			similarity += max(calculate_similarity(str1[4], str2[4], 4),
					calculate_similarity(str1[5], str2[5], 5), 0)
					* weight_director_writer;
			if (similarity >= 0.5)
				return true;
			// calculate_similarity(str1[2],str2[2]),
			// calculate_similarity(str1[11],str2[11]))*weight_title2;
			similarity += calculate_similarity(str1[6], str2[6], 6)
					* weight_actors2;
			similarity += calculate_similarity(str1[7], str2[7], 7)
					* weight_type2;
			similarity += calculate_similarity(str1[8], str2[8], 8)
					* weight_dict2;
			similarity += calculate_similarity(str1[9], str2[9], 9)
					* weight_language2;
			if (test)
				System.out.print(similarity + " ");
			if (similarity >= threshold) {
				if (!is_set) {
					if (max(calculate_similarity(str1[1], str2[1], 1),
							calculate_similarity(split_title2(str1[1]),
									split_title2(str2[1]), 1), 0) < 0.3
							&& calculate_similarity(str1[6], str2[6], 6) > 0.8) {
						is_unsure = true;
						is_set = true;
					}
				}
				return true;
			} else
				return false;

		}
	}

	// judge which is bigger according to pub_time
	private static String is_bigger(String str1, String str2) {
		String[] abc1 = str1.split("-");
		String[] abc2 = str2.split("-");
		if (abc1.length > 1 && abc2.length > 1) {
			if (abc1[1].compareTo(abc2[1]) > 0)
				return "T";
			else if (abc1[1].compareTo(abc2[1]) < 0)
				return "F";
			else if (abc1.length > 2 && abc2.length > 2) {
				if (abc1[2].compareTo(abc2[2]) > 0)
					return "T";
				else if (abc1[2].compareTo(abc2[2]) < 0)
					return "F";
				else
					return "NULL";
			} else
				return "NULL";
		} else
			return "NULL";
	}

	// get abstract name of the series movies
	private static String getAbstractName(String[][] allinfo, int[] Series_num,
			int count) {
		String temp = allinfo[Series_num[0]][1];
		for (int i = 1; i < count; i++)
			if (temp.length() > allinfo[Series_num[i]][1].length())
				temp = allinfo[Series_num[i]][1];
		// if it's the right abstract movie name, it should be the shortest.
		int len = temp.length();
		int like_count = 0;
		if (!temp.equals(allinfo[Series_num[0]][1].substring(0, len))
				|| !temp.equals(allinfo[Series_num[1]][1].substring(0, len))) {
			String str1 = split_title2(allinfo[Series_num[0]][1]);
			String str2 = split_title2(allinfo[Series_num[1]][1]);
			if (str1.equals(str2))
				return str1;
			else {
				for (int i = 0; i < len; i++)
					if (allinfo[Series_num[0]][1].substring(i, i + 1).equals(
							allinfo[Series_num[1]][1].substring(i, i + 1)))
						like_count += 1;
				if ((double) like_count / len > 0.5)
					return allinfo[Series_num[0]][1].substring(0, like_count);
				else
					return temp;
			}
		} else
			return temp;
	}

	public static void main(String[] args) {
		Date now = new Date();
		System.out.println("start!");
		System.out.println(now);
		// ***********************************************************************SETTING
		// data******
		final int RECORD_NUM = 28172;
		// test number:10;
		// final int RECORD_NUM=10;
		// all would be false when created;
		boolean[] is_compared = new boolean[RECORD_NUM];
		try {
			// *****************************************************************SETTING
			// input file******
			File file = new File("db_gxljc_dolphin--15-5-28.txt");
			File file2 = new File("IDforSameSeries-full.txt");
			File file3 = new File("IDforSameSeries.txt");
			File file4 = new File("IDforUnSure.txt");
			if (!file2.exists())
				file2.createNewFile();
			if (!file3.exists())
				file3.createNewFile();
			if (!file4.exists())
				file4.createNewFile();
			InputStreamReader fr = new InputStreamReader(new FileInputStream(
					file), "utf-8");
			OutputStreamWriter fw = new OutputStreamWriter(
					new FileOutputStream(file2), "utf-8");
			OutputStreamWriter fw1 = new OutputStreamWriter(
					new FileOutputStream(file3), "utf-8");
			OutputStreamWriter fw2 = new OutputStreamWriter(
					new FileOutputStream(file4), "utf-8");
			BufferedReader br = new BufferedReader(fr);
			BufferedWriter bw = new BufferedWriter(fw);
			BufferedWriter bw1 = new BufferedWriter(fw1);
			BufferedWriter bw2 = new BufferedWriter(fw2);
			// read file info,from the second line;
			String line = br.readLine();
			String[] info_title = new String[RECORD_NUM];
			String[] num_title = new String[RECORD_NUM];
			String[] second_title = new String[RECORD_NUM];
			String[][] allinfo = new String[RECORD_NUM][13];
			int[] Series_num = new int[50];
			int[] Series_rank = new int[50];
			int Series_count;
			String AbstractName;
			// processing info read;
			String[] info;
			// put all record into string array allinfo[][];
			for (int i = 0; i < RECORD_NUM; i++) {
				line = br.readLine();
				info = splitt(line);
				info_title[i] = info[1];
				num_title[i] = getNumAndSetitle(info_title[i])[0];
				second_title[i] = getNumAndSetitle(info_title[i])[1];
				info[1] = split_title(info[1]);
				// System.out.println(info[1]);
				// System.out.println(info[4]);
				// System.out.println(info[5]);
				// System.out.println(info[6]);
				allinfo[i] = info;
			}
			/*
			 * if(test){ for(int i=0;i<13;i++)
			 * System.out.println(allinfo[RECORD_NUM-1][i]); }
			 */
			for (int i = 0; i < RECORD_NUM; i++) {
				is_unsure = false;
				is_set = false;
				AbstractName = "null";
				Series_count = 1;
				Series_num[Series_count - 1] = i;
				if (!is_compared[i]) {
					is_compared[i] = true;
					for (int j = i + 1; j < RECORD_NUM; j++) {
						if (!is_compared[j]) {
							if (is_sameSeries(allinfo[i], allinfo[j])) {
								// to judge the series number
								Series_count = Series_count + 1;
								Series_num[Series_count - 1] = j;
								is_compared[j] = true;
							}
						}
					}
					if (Series_count > 1) {
						for (int k = 0; k < Series_count; k++)
							Series_rank[k] = 1;
						for (int p = 0; p < Series_count; p++)
							for (int q = p + 1; q < Series_count; q++) {
								if (allinfo[Series_num[p]][3]
										.compareTo(allinfo[Series_num[q]][3]) > 0)
									Series_rank[p] = Series_rank[p] + 1;
								if (allinfo[Series_num[p]][3]
										.compareTo(allinfo[Series_num[q]][3]) < 0)
									Series_rank[q] = Series_rank[q] + 1;
								else {
									if (is_bigger(allinfo[Series_num[p]][10],
											allinfo[Series_num[q]][10]) == "T")
										Series_rank[p] = Series_rank[p] + 1;
									else if (is_bigger(
											allinfo[Series_num[p]][10],
											allinfo[Series_num[q]][10]) == "F")
										Series_rank[q] = Series_rank[q] + 1;
								}

							}
						AbstractName = getAbstractName(allinfo, Series_num,
								Series_count);
					}
					if (AbstractName.equals("null"))
						AbstractName = info_title[i];
					for (int k = 0; k < Series_count; k++) {
						if (test) {
							System.out.print(allinfo[Series_num[k]][0]
									+ "      原名：");
							System.out.print(info_title[Series_num[k]]
									+ "      系列号：");
							if (Series_count > 1
									&& num_title[Series_num[k]].equals("NULL"))
								System.out.print(Series_rank[k] + "      系列名：");
							else
								System.out.print(num_title[Series_num[k]]
										+ "      系列名：");
							System.out.println(second_title[Series_num[k]]);
						}
						bw.write(allinfo[Series_num[k]][0] + "      原名：");
						bw.write(info_title[Series_num[k]] + "      系列号：");
						if (Series_count > 1
								&& num_title[Series_num[k]].equals("NULL"))
							bw.write(Series_rank[k] + "      系列名：");
						else
							bw.write(num_title[Series_num[k]] + "      系列名：");
						bw.write(second_title[Series_num[k]] + "\r\n");

						bw1.write(allinfo[Series_num[k]][0] + "###"
								+ info_title[Series_num[k]] + "###");

						if (is_unsure) {
							bw2.write(allinfo[Series_num[k]][0] + "      原名：");
							bw2.write(info_title[Series_num[k]] + "      系列号：");
							if (Series_count > 1
									&& num_title[Series_num[k]].equals("NULL"))
								bw2.write(Series_rank[k] + "      系列名：");
							else
								bw2.write(num_title[Series_num[k]]
										+ "      系列名：");
							bw2.write(second_title[Series_num[k]] + "\r\n");
						}

					}
					bw.write("\r\n");
					bw.write("--------------------------------------------------------------------\r\n");
					bw1.write(AbstractName);
					bw1.write("\r\n");

					if (is_unsure) {
						bw2.write("--------------------------------------------------------------------\r\n");
					}

					// System.out.println("-----------------------------------------------------------");
				}
				bw.flush();
				bw1.flush();
			}
			fr.close();
			fw.close();
			bw.close();
			bw1.close();
			bw2.close();
			now = new Date();
			System.out.println("end!");
			System.out.println(now);
		} catch (IOException e) {
			System.out.println("IO problem!");
		}
	}
}